#ifndef SIGNALDISPATCHER_H_
#define SIGNALDISPATCHER_H_

#include <string>
#include <stdexcept>
#include <map>

namespace uav
{
namespace comm
{

class SignalHandler;

/**
 * @brief POSIX signal dispatcher class.
 */
class SignalDispatcher
{
public:
	/**
	 * Returns the singleton dispatcher instance.
	 */
	static SignalDispatcher& instance()
	{
		static SignalDispatcher singleInstance;
		return singleInstance;
	}

	/**
	 * @brief Exception thrown when the dispatcher fails to attach a handler.
	 */
	class CannotAttachHandler : public std::runtime_error
	{
	public:
		CannotAttachHandler(const std::string &str) : runtime_error(str) {}
	};

	/**
	 * @brief Exception thrown when the dispatcher fails to detach a handler.
	 */
	class CannotDetachHandler : public std::runtime_error
	{
	public:
		CannotDetachHandler(const std::string &str) : runtime_error(str) {}
	};

	/**
	 * Attach a signal handler for the specifed signal to the dispatcher.
	 *
	 * The SignalHandler::handleSignal function will be called every time
	 * the specified signal is received. The signal handler should not be
	 * destroyed while it is attached to the dispatcher. The signal
	 * handler should call detachHandler() from its destructor.
	 */
	void attachHandler(int sigNum, SignalHandler &handler)
		throw(CannotAttachHandler);

	/**
	 * Detach the specified signal handler from the dispatcher.
	 *
	 * The signal handler will stop being called upon when the corresponding
	 * signal is received. This function has no effect if the specified
	 * signal handler is not attached to the dispatcher when the function is
	 * called.
	 */
	void detachHandler(int sigNum, const SignalHandler &handler)
		throw(CannotDetachHandler, std::logic_error);

private:
	typedef std::multimap<int, SignalHandler*> HandlerList;
	HandlerList handlerList;

	typedef std::map<int, struct sigaction> SigActionList;
	SigActionList oldActionList;

	/**
	 * Static function used to attach the dispatcher to a signal using sigaction().
	 */
	static void actionHandler(int sigNum);

	// Singleton constructor
	SignalDispatcher() {}

	// Prevent subclassing
	~SignalDispatcher() {}

	// Prevent copying
	SignalDispatcher(const SignalDispatcher &other);
	SignalDispatcher& operator=(const SignalDispatcher &other);
};

}}

#endif
